﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Xml;
using SHomeWorkshop.LunarConcept.Adorners;
using SHomeWorkshop.LunarConcept.Controls;
using SHomeWorkshop.LunarConcept.Enums;
using SHomeWorkshop.LunarConcept.ModifingManager;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.Widgets.Interfaces;
using System.Collections.Generic;

namespace SHomeWorkshop.LunarConcept.Widgets
{
    /// <summary>
    /// 创建时间：2012年1月20日前
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：提供一个矩形部件。
    /// </summary>
    public class RectangleWidget : ShapeWidget, ICanSameSize, ICanBeLinkedWidget, ITextRotate, IRadius
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// [静态构造方法]
        /// </summary>
        static RectangleWidget()
        {
            dashArray = new DoubleCollection() { 2, 2 };
            contextMenu = (ContextMenu)Globals.MainWindow.MainGrid.FindResource("CMDicRectangleWidget");
        }

        /// <summary>
        /// [构造方法]
        /// </summary>
        /// <param name="pageEditor"></param>
        public RectangleWidget(PageEditor editor)
            : base(editor)
        {
            this.ContextMenu = contextMenu;

            widgetType = Enums.WidgetTypes.Rectangle;
            widgetClassLocalName = Widget.GetWidgetClassLocalName(this.GetType().Name);

            mainRectangle.Fill = null;
            mainRectangle.Stroke = WidgetForeColor;
            mainRectangle.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(mainRectangle_PreviewMouseLeftButtonDown);
            mainRectangle.PreviewMouseRightButtonUp += new MouseButtonEventHandler(mainRectangle_PreviewMouseRightButtonUp);

            this.mainCanvas.Children.Add(mainRectangle);

            Canvas.SetZIndex(mainRectangle, 0);

            startCtrl = new LineCtrlAdorner(this.mainRectangle, this, Brushes.Red) { Visibility = Visibility.Hidden };
            endCtrl = new LineCtrlAdorner(this.mainRectangle, this, Brushes.Blue) { Visibility = Visibility.Hidden };

            //中点装饰器。
            this.centerAdorner = new WidgetCenterAdorner(this.mainRectangle, this, Brushes.Black) { ToolTip = "按鼠标左键向外拖动，生成关系节点" };

            this.centerAdorner.PreviewMouseRightButtonUp += new MouseButtonEventHandler(centerAdorner_PreviewMouseRightButtonUp);

            this.commentAdorner = new CommentAdorner(this.mainRectangle, this) { Visibility = System.Windows.Visibility.Collapsed };//默认不显示。
            this.commentAdorner.MouseLeftButtonUp += new MouseButtonEventHandler(commentAdorner_MouseLeftButtonUp);

            this.hyperLinkAdorner = new HyperLinkAdorner(this.mainRectangle, this) { Visibility = Visibility.Collapsed };
            this.hyperLinkAdorner.MouseLeftButtonUp += new MouseButtonEventHandler(hyperLinkAdorner_MouseLeftButtonUp);

            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.mainCanvas);
            if (adornerLayer == null)
            {
                MessageBox.Show("　　未找到Widget的装饰层！", Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
            }
            else
            {
                //这个要放在最底层
                this.presentationAreaAdorner = new PresentationAreaAdorner(this.MainCanvas, this);
                this.presentationAreaAdorner.PreviewMouseLeftButtonDown += mainRectangle_PreviewMouseLeftButtonDown;
                this.presentationAreaAdorner.PreviewMouseRightButtonUp += mainRectangle_PreviewMouseRightButtonUp;
                adornerLayer.Add(presentationAreaAdorner);

                adornerLayer.Add(this.startCtrl);
                adornerLayer.Add(this.endCtrl);
                adornerLayer.Add(this.centerAdorner);

                //添加标记装饰层

                this.markAdorner = new RectangleMarkAdorner(this.mainCanvas, this);
                this.markAdorner.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(markAdorner_PreviewMouseLeftButtonDown);
                this.markAdorner.PreviewMouseRightButtonUp += new MouseButtonEventHandler(mainRectangle_PreviewMouseRightButtonUp);
                adornerLayer.Add(markAdorner);

                adornerLayer.Add(this.commentAdorner);//这个要在各具体部件类中添加。
                adornerLayer.Add(this.hyperLinkAdorner);//这个要在各具体部件类中添加。
            }

            startCtrl.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(startCtrl_MouseLeftButtonDown);
            endCtrl.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(endCtrl_MouseLeftButtonDown);

            startCtrl.ToolTip = endCtrl.ToolTip = "双击鼠标左键设置备注文本";

            centerAdorner.MouseLeftButtonDown += new MouseButtonEventHandler(centerAdorner_MouseLeftButtonDown);

            //最后添加文本面板。
            this.mainCanvas.Children.Add(this.mainTextPanel);
            Canvas.SetZIndex(this.mainTextPanel, 2);

            this.ControlHandlerDoubleClicked += RectangleWidget_ControlHandlerDoubleClicked;
        }

        private void RectangleWidget_ControlHandlerDoubleClicked(object sender, MouseButtonEventArgs e)
        {
            //不再以双击设置演示区，而是双击设置备注文本，演示区毕竟用得少。
            LunarMessage.Warning(Commands.SetCommentTextCommand.Execute());

            //LunarMessage.Warning(Commands.SetIsPresentationAreaCommand.Execute(!this.IsPresentationArea));
            //if (this.isPresentationArea && string.IsNullOrWhiteSpace(this.MarkText))
            //{
            //    //SetMarkText();
            //}
        }

        #endregion


        #region 字段与属性===================================================================================================

        public override Point BottomRight
        {
            get
            {
                double minLeft, minTop, maxRight, maxBottom;

                minLeft = Math.Min(startPoint.X, endPoint.X);
                maxRight = Math.Max(startPoint.X, endPoint.X);

                minTop = Math.Min(startPoint.Y, endPoint.Y);
                maxBottom = Math.Max(startPoint.Y, endPoint.Y);

                return new Point(maxRight, maxBottom);
            }
        }

        protected WidgetCenterAdorner centerAdorner;
        /// <summary>
        /// [只读]用于“拖出自动连接线”的装饰器。一般应在中心位置。
        /// </summary>
        public WidgetCenterAdorner CenterAdorner
        {
            get { return centerAdorner; }
        }

        /// <summary>
        /// 本类通用上下文菜单。
        /// </summary>
        private static ContextMenu contextMenu;

        /// <summary>
        /// 点划线定义。
        /// </summary>
        private static DoubleCollection dashArray;

        /// <summary>
        /// 指明正在拖动的是哪个控制点。
        /// </summary>
        private ControlDraggingType draggingType = ControlDraggingType.None;

        private Point EndBasePoint
        {
            get
            {
                return new Point(Math.Max(startPoint.X, endPoint.X), Math.Max(startPoint.Y, endPoint.Y));
            }
        }

        private LineCtrlAdorner endCtrl;
        /// <summary>
        /// [只读]尾控制点（装饰器）。
        /// </summary>
        public LineCtrlAdorner EndCtrl
        {
            get { return endCtrl; }
        }

        private Point endPoint = new Point();
        /// <summary>
        /// [读写]终点。
        /// </summary>
        [Tools.LunarProperty("EndPoint", PropertyDateType.Point)]
        public Point EndPoint
        {
            get { return endPoint; }
            set
            {
                endPoint = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.EndPointTag, value.ToString());
                }

                RefreshLocation();
            }
        }

        private bool fixTextWidth = false;
        /// <summary>
        /// [读写]是否绑定文本块最大宽度。（文本块最小宽度为20）。
        /// </summary>
        [Tools.LunarProperty("FixTextWidth", PropertyDateType.Bool)]
        public bool FixTextWidth
        {
            get { return fixTextWidth; }
            set
            {
                fixTextWidth = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.FixTextWidthTag, fixTextWidth.ToString());
                }

                RefreshFixTextWidth();
            }
        }

        protected double radius = 0.0;
        /// <summary>
        /// [读写]是否圆角矩形。
        /// </summary>
        [Tools.LunarProperty("Radius", PropertyDateType.Double)]
        public double Radius
        {
            get
            {
                return this.radius;
            }
            set
            {
                radius = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.RadiusTag, radius.ToString());
                }

                RefreshRadius(this.OuterRect);
            }
        }

        /// <summary>
        /// [只读]表示当前部件是否被某个连接线挂接着。
        /// </summary>
        public bool IsLinked
        {
            get
            {
                if (this.masterEditor == null) return false;

                foreach (UIElement ue in this.masterEditor.Children)
                {
                    ILinkableLine linkedLine = ue as ILinkableLine;
                    if (linkedLine == null) continue;

                    if (linkedLine.StartMasterId == this.id || linkedLine.EndMasterId == this.id) return true;
                }

                return false;
            }
        }

        private bool isMarkTextCollapsed = false;
        /// <summary>
        /// [读写]是否折叠显示右下角的标记文本（一般用作选择题答案）。
        /// </summary>
        [Tools.LunarProperty("IsMarkTextCollapsed", PropertyDateType.Bool)]
        public bool IsMarkTextCollapsed
        {
            get { return isMarkTextCollapsed; }
            set
            {
                isMarkTextCollapsed = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.IsMarkTextCollapsedTag, isMarkTextCollapsed.ToString());
                }
                this.RefreshMarkText();
            }
        }

        /// <summary>
        /// [读写]是否处于“被选定”状态。
        /// </summary>
        public override bool IsSelected
        {
            get { return base.IsSelected; }
            set
            {
                base.IsSelected = value;

                //显示控制点。
                if (isSelected)
                {
                    startCtrl.Visibility =
                        endCtrl.Visibility = Visibility.Visible;
                }
                else
                {
                    startCtrl.Visibility =
                        endCtrl.Visibility = Visibility.Hidden;
                }
            }
        }

        [Tools.LunarProperty("WidgetLineWidth", PropertyDateType.Double)]
        public override double WidgetLineWidth
        {
            get
            {
                return base.WidgetLineWidth;
            }
            set
            {
                base.WidgetLineWidth = value;
                this.RefreshMarkText();
                this.RefreshIsPresentationArea();
            }
        }

        private Rectangle mainRectangle = new Rectangle() { Cursor = Cursors.Hand };
        /// <summary>
        /// [只读]用以呈现的矩形。
        /// </summary>
        public Rectangle MainRectangle
        {
            get { return mainRectangle; }
        }

        /// <summary>
        /// 显示“ＡＢＣＤ”等字母的装饰器（用来显示客观题的答案）。
        /// </summary>
        private RectangleMarkAdorner markAdorner;

        private string markText = string.Empty;
        /// <summary>
        /// [读写]标记文本。一般用于显示客观题答案。
        /// </summary>
        [Tools.LunarProperty("MarkText", PropertyDateType.String)]
        public string MarkText
        {
            get { return markText; }
            set
            {
                this.markText = value;

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.MarkTextTag, value);
                }

                this.RefreshMarkText();
            }
        }

        private void SetMarkText()
        {
            var oldMarkText = this.MarkText;

            Dialogs.TextInputBox tiBox = new Dialogs.TextInputBox(Globals.MainWindow,
                "　　请在下框中输入矩形的新标记文本。\r\n\r\n　　★注意：如果此矩形被定义为【演示区域】，则这里标记文本将决定演示的顺序。",
                Globals.AppName, oldMarkText);

            if (tiBox.ShowDialog() == true)
            {
                string result = Commands.TextCommands.RunTextCommand.Run("mk_" + tiBox.TbxInput.Text);
                if (result != string.Empty)
                {
                    MessageBox.Show("　　设置矩形标记文本出错。异常信息如下：\r\n" + result, Globals.AppName,
                         MessageBoxButton.OK, MessageBoxImage.Warning);
                }
            }
        }

        private PresentationAreaAdorner presentationAreaAdorner;

        private bool isPresentationArea = false;
        /// <summary>
        /// [读写]是否演示区域。如为真，则“按路径演示”会演示此矩形部件所在区域（但不会演示此矩形本身）。
        /// </summary>
        [Tools.LunarProperty("IsPresentationArea", PropertyDateType.Bool)]
        public bool IsPresentationArea
        {
            get
            {
                return isPresentationArea;
            }

            set
            {
                isPresentationArea = value;

                this.xmlData?.SetAttribute(XmlTags.IsPresentationAreaTag, value.ToString());

                this.RefreshIsPresentationArea();
            }
        }

        private string iconXamlText = string.Empty;
        /// <summary>
        /// [读写]用于存储Xaml文本，此文本用于自动载入为新图标。
        /// </summary>
        [Tools.LunarProperty("IconXamlText", PropertyDateType.String)]
        public string IconXamlText
        {
            get { return iconXamlText; }
            set
            {
                this.iconXamlText = value;
                if (this.xmlData != null)
                {
                    XmlNode iconXamlNode = this.xmlData.SelectSingleNode(XmlTags.IconXamlTextTag);
                    if (iconXamlNode == null)
                    {
                        this.xmlData.AppendXmlAsChild("<" + XmlTags.IconXamlTextTag + ">" + value + "</" + XmlTags.IconXamlTextTag + ">");
                    }
                    else
                    {
                        iconXamlNode.InnerXml = value;
                    }
                }

                this.RefreshIconXamlText();
            }
        }

        private Rect movingRect;
        /// <summary>
        /// 部件正在被拖动时的外边框。
        /// </summary>
        public Rect MovingRect
        {
            get
            {
                return movingRect;
            }
        }

        /// <summary>
        /// 返回文本区的实际高度。
        /// </summary>
        public double TextPanelHeight
        {
            get
            {
                if (this.mainTextPanel != null)
                {
                    this.mainTextPanel.InvalidateArrange();
                    this.mainTextPanel.UpdateLayout();
                    return this.mainTextPanel.ActualHeight;
                    //return this.mainTextPanel.RenderSize.Height;//取不到及时的值。
                }
                else return 0;
            }
        }


        private double textRotateAngle = 0;
        /// <summary>
        /// [读写]文本旋转角度。取值范围：[-180,180]。
        /// </summary>
        [Tools.LunarProperty("TextRotateAngle", PropertyDateType.Double)]
        public double TextRotateAngle
        {
            get { return textRotateAngle; }
            set
            {
                if (value > 180)
                {
                    textRotateAngle = 180;
                }
                else if (value < -180)
                {
                    textRotateAngle = -180;
                }
                else
                {
                    textRotateAngle = value;
                }

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.TextRotateAngleTag, textRotateAngle.ToString());
                }

                this.RefreshTextRotateAngle();
            }
        }

        private Enums.TextAreaAlignment textAreaAlignment = TextAreaAlignment.Center;
        /// <summary>
        /// [读写]文本区域在“自动折行”被关闭的情况下，如何对齐文本区域（不是文本区域内部文本段落的对齐）。
        /// </summary>
        [Tools.LunarProperty("TextAreaAlignment", PropertyDateType.TextAreaAlignment)]
        public Enums.TextAreaAlignment TextAreaAlignment
        {
            get { return textAreaAlignment; }
            set
            {
                textAreaAlignment = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.TextAreaAlignmentTag, this.textAreaAlignment.ToString());
                }
                RefreshTextPanelLocatin();
            }
        }

        private Point StartBasePoint
        {
            get
            {
                return new Point(Math.Min(startPoint.X, endPoint.X), Math.Min(startPoint.Y, endPoint.Y));
            }
        }

        private LineCtrlAdorner startCtrl;
        /// <summary>
        /// [只读]首控制点（装饰器）。
        /// </summary>
        public LineCtrlAdorner StartCtrl
        {
            get { return startCtrl; }
        }

        private Point startPoint = new Point();
        /// <summary>
        /// [读写]起点。
        /// </summary>
        [Tools.LunarProperty("StartPoint", PropertyDateType.Point)]
        public Point StartPoint
        {
            get { return startPoint; }
            set
            {
                startPoint = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.StartPointTag, value.ToString());
                }

                RefreshLocation();
            }
        }

        public override Point TopLeft
        {
            get
            {
                double minLeft, minTop, maxRight, maxBottom;

                minLeft = Math.Min(startPoint.X, endPoint.X);
                maxRight = Math.Max(startPoint.X, endPoint.X);

                minTop = Math.Min(startPoint.Y, endPoint.Y);
                maxBottom = Math.Max(startPoint.Y, endPoint.Y);

                return new Point(minLeft, minTop);
            }
        }


        #endregion


        #region 方法=========================================================================================================

        /// <summary>
        /// 根据XmlData的信息，生成部件内容，设置部件格式。
        /// </summary>
        public override void Build()
        {
            base.Build();

            if (this.xmlData == null) return;

            XmlAttribute attrStartPoint = this.xmlData.GetAttribute(XmlTags.StartPointTag);
            if (attrStartPoint != null)
            {
                this.startPoint = Point.Parse(attrStartPoint.Value);
            }

            XmlAttribute attrEndPoint = this.xmlData.GetAttribute(XmlTags.EndPointTag);
            if (attrEndPoint != null)
            {
                this.endPoint = Point.Parse(attrEndPoint.Value);
            }

            XmlAttribute attrFixTextWidth = this.xmlData.GetAttribute(XmlTags.FixTextWidthTag);
            if (attrFixTextWidth != null)
            {
                this.fixTextWidth = bool.Parse(attrFixTextWidth.Value);
            }

            XmlAttribute attrRadius = this.xmlData.GetAttribute(XmlTags.RadiusTag);
            if (attrRadius != null)
            {
                this.radius = double.Parse(attrRadius.Value);
            }

            XmlAttribute attrIsMarkTextCollapsed = this.xmlData.GetAttribute(XmlTags.IsMarkTextCollapsedTag);
            if (attrIsMarkTextCollapsed != null)
            {
                this.isMarkTextCollapsed = bool.Parse(attrIsMarkTextCollapsed.Value);
            }

            XmlAttribute attrMark = this.xmlData.GetAttribute(XmlTags.MarkTextTag);
            if (attrMark != null)
            {
                this.markText = attrMark.Value;
            }
            else
            {
                this.markText = string.Empty;
            }

            var attrIsPresentationArea = this.xmlData.GetAttribute(XmlTags.IsPresentationAreaTag);
            if (attrIsPresentationArea != null)
            {
                this.isPresentationArea = bool.Parse(attrIsPresentationArea.Value);
            }

            XmlAttribute attrTextRotateAngle = this.xmlData.GetAttribute(XmlTags.TextRotateAngleTag);
            if (attrTextRotateAngle != null)
            {
                this.textRotateAngle = double.Parse(attrTextRotateAngle.Value);
            }
            else
            {
                this.textRotateAngle = 0;
            }

            XmlAttribute attrTextAreaAlignment = this.xmlData.GetAttribute(XmlTags.TextAreaAlignmentTag);
            if (attrTextAreaAlignment != null)
            {
                this.textAreaAlignment = (Enums.TextAreaAlignment)Enum.Parse(typeof(Enums.TextAreaAlignment), attrTextAreaAlignment.Value);
            }
            else
            {
                this.textAreaAlignment = Enums.TextAreaAlignment.Center;
            }

            XmlNode iconXamlNode = this.xmlData.SelectSingleNode(XmlTags.IconXamlTextTag);
            if (iconXamlNode != null)
            {
                this.iconXamlText = iconXamlNode.InnerXml;
            }

            this.RefreshTextRotateAngle();

            this.RefreshLocation();//已含this.RefreshIsRoundRectangle();

            this.RefreshMarkText();
            this.RefreshIsPresentationArea();

            this.RefreshRadius(this.OuterRect);
            this.RefreshIconXamlText();

            //此类是下面这几个属性的“最终实现类”。这些属性的值都已在基类确定。因此调用,
            this.RefreshWidgetBackColor();
            this.RefreshWidgetLineColor();
            this.RefreshWidgetLineWidth();
            this.RefreshLineDash();
            this.RefreshRadius(this.OuterRect);
        }

        protected override void BuildStyleProperties()
        {
            base.BuildStyleProperties();

            if (this.xmlData == null) return;

            WidgetStyle defStyleOfDoc;
            if (this.masterEditor != null && this.masterEditor.MasterManager != null)
            {
                defStyleOfDoc = this.masterEditor.MasterManager.GetDefaultWidgetStyle(this.WidgetClassName);
            }
            else
            {
                defStyleOfDoc = WidgetStyle.FromWidgetClassName(this.WidgetClassName);
            }

            //取线型。
            XmlAttribute attrRadius = this.xmlData.GetAttribute(XmlTags.RadiusTag);
            if (attrRadius != null)
            {
                radius = double.Parse(attrRadius.Value);
            }
            else
            {
                radius = defStyleOfDoc.Radius;
            }
        }

        public override void BuildWidgetStylePropertiesAndRefresh()
        {
            base.BuildWidgetStylePropertiesAndRefresh();

            //此类是下面这几个属性的“最终实现类”。这些属性的值都已在基类确定。因此调用,
            this.RefreshWidgetBackColor();
            this.RefreshWidgetLineColor();
            this.RefreshWidgetLineWidth();
            this.RefreshLineDash();
            this.RefreshRadius(this.OuterRect);

            //无意义
            //this.RefreshArrows();
            //this.RefreshWidgetPadding();

            //这几个在Widget类中已经调用。
            //this.RefreshWidgetForeColor();
            //this.RefreshIsShadowVisible();
            //this.RefreshWidgetOpacity();
        }

        /// <summary>
        /// 关联事件。右击中心装饰器时，活动此部件。
        /// </summary>
        void centerAdorner_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            mainRectangle_PreviewMouseRightButtonUp(sender, e);
        }

        private void DrawLine()
        {
            DrawLine(this.startPoint, this.endPoint, false);
        }

        /// <param name="startPoint">首端点。</param>
        /// <param name="endPoint">尾端点。</param>
        /// <param name="isShift">是否按住Shift键拖动。</param>
        private void DrawLine(Point startPoint, Point endPoint, bool isShift)
        {
            Point startBasePt, endBasePt;

            startBasePt = new Point(Math.Min(startPoint.X, endPoint.X),
                   Math.Min(startPoint.Y, endPoint.Y));
            endBasePt = new Point(Math.Max(startPoint.X, endPoint.X),
              Math.Max(startPoint.Y, endPoint.Y));

            if (isShift)
            {
                if (startPoint.Y > endPoint.Y)
                {
                    endBasePt.Y = startBasePt.Y + (endBasePt.X - startBasePt.X);
                }
                else
                {
                    startBasePt.Y = endBasePt.Y - (endBasePt.X - startBasePt.X);
                }
            }

            Canvas.SetLeft(mainRectangle, startBasePt.X);
            Canvas.SetTop(mainRectangle, startBasePt.Y);

            mainRectangle.Width = (endBasePt.X - startBasePt.X);
            mainRectangle.Height = (endBasePt.Y - startBasePt.Y);

            //刷新圆角。
            this.RefreshRadius(new Rect(startBasePt, endBasePt));

            //移动部件控制点时，要刷新连接线的。
            this.movingRect = new Rect(startBasePt, endBasePt);

            //注意：与其它线型部件不同。Ellipse和Rectangle的装饰位置坐标有区别。
            startCtrl.CenterPoint = new Point(startPoint.X - startBasePt.X, startPoint.Y - startBasePt.Y);
            endCtrl.CenterPoint = new Point(endPoint.X - startBasePt.X, endPoint.Y - startBasePt.Y);//这里也用startBasePt

            LocateTextPanel(startBasePt, endBasePt);
            LocateXamlIcon(startBasePt, endBasePt);

            var newRect = new Rect(startPoint, endPoint);
            this.RefreshMarkText(newRect);
            this.RefreshIsPresentationArea(newRect);
        }

        private void LocateXamlIcon(Point startBasePt, Point endBasePt)
        {
            if (this.xamlIconFrameWorkElement != null)
            {
                Canvas.SetLeft(this.xamlIconFrameWorkElement, Math.Min(startBasePt.X, endBasePt.X));
                Canvas.SetTop(this.xamlIconFrameWorkElement, Math.Min(startBasePt.Y, endBasePt.Y));

                this.xamlIconFrameWorkElement.Width = Math.Abs(endBasePt.X - startBasePt.X);
                this.xamlIconFrameWorkElement.Height = Math.Abs(endBasePt.Y - startBasePt.Y);
            }
        }

        /// <summary>
        /// 重定文本位置。
        /// </summary>
        /// <param name="startBasePt">首端基准点。</param>
        /// <param name="endBasePt">尾基准点。</param>
        private void LocateTextPanel(Point startBasePt, Point endBasePt)
        {
            RefreshFixTextWidth(startBasePt, endBasePt);//注意顺序。

            Point center = new Point(startBasePt.X + (endBasePt.X - startBasePt.X) / 2,
                startBasePt.Y + (endBasePt.Y - startBasePt.Y) / 2);

            Point textStart;

            if (fixTextWidth)
            {
                textStart = new Point(center.X - this.mainTextPanel.ActualWidth / 2 - this.mainTextPanel.Margin.Left,
                    Math.Min(startBasePt.Y, endBasePt.Y) + 2 - this.mainTextPanel.Margin.Top + this.widgetLineWidth);
            }
            else
            {
                switch (this.textAreaAlignment)
                {
                    case Enums.TextAreaAlignment.Left:
                        {
                            textStart = new Point(startBasePt.X, center.Y - this.mainTextPanel.ActualHeight / 2 - this.mainTextPanel.Margin.Top);
                            break;
                        }
                    case Enums.TextAreaAlignment.Right:
                        {
                            textStart = new Point(endBasePt.X - this.mainTextPanel.ActualWidth - this.mainTextPanel.Margin.Left - this.mainTextPanel.Margin.Right,
                                center.Y - this.mainTextPanel.ActualHeight / 2 - this.mainTextPanel.Margin.Top);
                            break;
                        }
                    case Enums.TextAreaAlignment.Top:
                        {
                            textStart = new Point(center.X - this.mainTextPanel.ActualWidth / 2 - this.mainTextPanel.Margin.Left, startBasePt.Y);
                            break;
                        }
                    case Enums.TextAreaAlignment.Bottom:
                        {
                            textStart = new Point(center.X - this.mainTextPanel.ActualWidth / 2 - this.mainTextPanel.Margin.Left,
                                endBasePt.Y - this.mainTextPanel.ActualHeight - this.mainTextPanel.Margin.Top - this.mainTextPanel.Margin.Bottom);
                            break;
                        }
                    case Enums.TextAreaAlignment.TopLeft:
                        {
                            textStart = startBasePt; break;
                        }
                    case Enums.TextAreaAlignment.TopRight:
                        {
                            textStart = new Point(endBasePt.X - this.mainTextPanel.ActualWidth - this.mainTextPanel.Margin.Left - this.mainTextPanel.Margin.Right,
                                startBasePt.Y);
                            break;
                        }
                    case Enums.TextAreaAlignment.BottomLeft:
                        {
                            textStart = new Point(startBasePt.X,
                                endBasePt.Y - this.mainTextPanel.ActualHeight - this.mainTextPanel.Margin.Top - this.mainTextPanel.Margin.Bottom);
                            break;
                        }
                    case Enums.TextAreaAlignment.BottomRight:
                        {
                            textStart = new Point(endBasePt.X - this.mainTextPanel.ActualWidth - this.mainTextPanel.Margin.Left - this.mainTextPanel.Margin.Right,
                                endBasePt.Y - this.mainTextPanel.ActualHeight - this.mainTextPanel.Margin.Top - this.mainTextPanel.Margin.Bottom);
                            break;
                        }
                    default:
                        {
                            string backColorName = BrushManager.GetName(this.widgetBackColor);
                            if (backColorName != null && backColorName.Contains("Bubble"))
                            {
                                double offset = Math.Abs(endBasePt.Y - startBasePt.Y) / 16;
                                //气泡背景，有个偏移量。
                                //要保证气泡中的文字垂直对齐，测试得出的偏移量约值是16分之1。

                                if (backColorName.Contains("Top"))
                                {
                                    textStart = new Point(center.X - this.mainTextPanel.ActualWidth / 2 - this.mainTextPanel.Margin.Left,
                                        center.Y - this.mainTextPanel.ActualHeight / 2 - this.mainTextPanel.Margin.Top + offset);
                                }
                                else
                                {
                                    textStart = new Point(center.X - this.mainTextPanel.ActualWidth / 2 - this.mainTextPanel.Margin.Left,
                                        center.Y - this.mainTextPanel.ActualHeight / 2 - this.mainTextPanel.Margin.Top - offset);
                                }
                            }
                            else
                            {
                                textStart = new Point(center.X - this.mainTextPanel.ActualWidth / 2 - this.mainTextPanel.Margin.Left,
                                    center.Y - this.mainTextPanel.ActualHeight / 2 - this.mainTextPanel.Margin.Top);
                            }

                            break;
                        }
                }
            }

            Canvas.SetLeft(this.mainTextPanel, textStart.X);
            Canvas.SetTop(this.mainTextPanel, textStart.Y);

            //textPanelTopLeftToWidgetTopLeft = new Point(textStart.X - TopLeft.X, textStart.Y - TopLeft.Y);
        }

        /// <summary>
        /// 文本区域到部件左上角的距离——这个用在拖动部件时定位。
        /// </summary>
        //private Point textPanelTopLeftToWidgetTopLeft;

        public override void DropWidget(ModifingItem<Action, ModifingInfo> mi, Point mousePoint)
        {
            if (mi == null) return;
            if (masterEditor == null) return;

            Point globalLocation = masterEditor.MouseInfo.LeftButtonPreviewPoint;

            Point newStartPoint = new Point(
                startPoint.X - globalLocation.X + mousePoint.X, startPoint.Y - globalLocation.Y + mousePoint.Y);

            Point newEndPoint = new Point(
                endPoint.X - globalLocation.X + mousePoint.X, endPoint.Y - globalLocation.Y + mousePoint.Y);

            #region 自动中心吸附
            bool autoAlignment = Globals.MainWindow.RtbtnAutoAlignment.IsChecked == true;

            if (autoAlignment)
            {
                double hOffset = double.MaxValue, vOffset = double.MaxValue;
                if (autoAlignment)
                {
                    //尝试自动对齐

                    //先尝试中心坐标对齐
                    //需要取出最接近的位置
                    Point center = new Point(newStartPoint.X + this.OuterRect.Width / 2, newStartPoint.Y + this.OuterRect.Height / 2);

                    foreach (UIElement ue in this.MasterEditor.MainCanvas.Children)
                    {
                        Widget widget = ue as ContentWidget;
                        if (widget == null)
                        {
                            widget = ue as ShapeWidget;
                            if (widget == null) continue;
                        }

                        if (widget == this) continue;
                        if (widget.MasterEditor.GetSelectedWidgetsList().Contains(widget)) continue;

                        Point widgetCenter = new Point(widget.OuterRect.Left + widget.OuterRect.Width / 2, widget.OuterRect.Top + widget.OuterRect.Height / 2);
                        double h = double.MaxValue, v = double.MaxValue, tmph = double.MaxValue, tmpv = double.MaxValue;

                        tmph = widgetCenter.X - center.X;
                        tmpv = widgetCenter.Y - center.Y;

                        if (Math.Abs(tmph) < Math.Abs(h)) h = tmph;
                        if (Math.Abs(tmpv) < Math.Abs(v)) v = tmpv;

                        if (Math.Abs(h) < Math.Abs(hOffset)) hOffset = h;
                        if (Math.Abs(v) < Math.Abs(vOffset)) vOffset = v;
                    }
                }

                //自动吸附对齐会造成很迷惑人的效果。取消之。2014年7月26日
                //if (hOffset < double.MaxValue && Math.Abs(hOffset) < 10)
                //{
                //    newStartPoint.X += hOffset;
                //    newEndPoint.X += hOffset;
                //}

                //if (vOffset < double.MaxValue && Math.Abs(vOffset) < 10)
                //{
                //    newStartPoint.Y += vOffset;
                //    newEndPoint.Y += vOffset;
                //}
            }
            #endregion

            Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name,
                XmlTags.StartPointTag, startPoint.ToString(),
                newStartPoint.ToString());
            StartPoint = newStartPoint;

            Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name,
                XmlTags.EndPointTag, endPoint.ToString(),
                newEndPoint.ToString());
            EndPoint = newEndPoint;

            mi.ModifingInfo.NewMainSelectedWidgetID = this.id;
            mi.AddAction(actStartPoint);
            mi.AddAction(actEndPoint);
        }

        public override void DropWidgetControler(Point newOutSidePoint, ModifingItem<Action, ModifingInfo> mi)
        {
            if (mi == null || mi.ModifingInfo == null) return;
            if (masterEditor == null || masterEditor.MasterManager == null) return;

            ModifingInfo info = mi.ModifingInfo;

            bool isShift = false;

            KeyStates ksRightShift = Keyboard.GetKeyStates(Key.RightShift);
            KeyStates ksLeftShift = Keyboard.GetKeyStates(Key.LeftShift);

            if ((ksLeftShift & KeyStates.Down) > 0 || (ksRightShift & KeyStates.Down) > 0)
            {
                isShift = true;
            }

            switch (draggingType)
            {
                case ControlDraggingType.Start:
                    {
                        info.ModifingDescription = "拖动矩形首端点";

                        if (isShift)
                        {
                            if (newOutSidePoint.Y > endPoint.Y)
                            {
                                newOutSidePoint.Y = endPoint.Y + Math.Abs(newOutSidePoint.X - endPoint.X);
                            }
                            else
                            {
                                newOutSidePoint.Y = endPoint.Y - Math.Abs(newOutSidePoint.X - endPoint.X);
                            }
                        }

                        Action actDraggingLineHeader = new Action(masterEditor.Id, id, this.GetType().Name,
                            XmlTags.StartPointTag, startPoint.ToString(), newOutSidePoint.ToString());
                        StartPoint = newOutSidePoint;

                        info.NewMainSelectedWidgetID = this.id;
                        mi.AddAction(actDraggingLineHeader);
                        break;
                    }
                case ControlDraggingType.End:
                    {
                        info.ModifingDescription = "拖动矩形尾端点";

                        if (isShift)
                        {
                            if (newOutSidePoint.Y > startPoint.Y)
                            {
                                newOutSidePoint.Y = startPoint.Y + Math.Abs(newOutSidePoint.X - startPoint.X);
                            }
                            else
                            {
                                newOutSidePoint.Y = startPoint.Y - Math.Abs(newOutSidePoint.X - startPoint.X);
                            }
                        }

                        Action actDraggingLineHeader = new Action(masterEditor.Id, id, this.GetType().Name,
                            XmlTags.EndPointTag, endPoint.ToString(), newOutSidePoint.ToString());
                        EndPoint = newOutSidePoint;

                        info.NewMainSelectedWidgetID = this.id;
                        mi.AddAction(actDraggingLineHeader);
                        break;
                    }
            }

            //刷新连接线首尾端点的位置。
            List<ILinkableLine> linkedLines = this.GetLinkedLines();
            this.masterEditor.RefreshLinkedLines(mi, linkedLines);
        }

        /// <summary>
        /// 这个虚方法是用以查看本部件是否在选定框的内部。
        /// 线型部件，各有各的计算办法。
        /// </summary>
        /// <param name="rect"></param>
        /// <returns></returns>
        public override bool IsInRect(Rect rect)
        {
            //return base.IsInRect(rect);//这个要屏蔽。
            bool isInRect = base.IsInRect(rect);
            if (isInRect)
            {
                return true;
            }
            else
            {
                Rect virtualRect = new Rect(startPoint, endPoint);
                return rect.IntersectsWith(virtualRect);
            }
        }

        void mainRectangle_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //双击编辑文本
            if (e.ClickCount == 2)
            {
                this.SelectOnlySelf();
                if (Globals.MainWindow.IsPresentatingByPath == false)
                {
                    this.Edit();
                }
                return;
            }

            ModifingItem<Action, ModifingInfo> mi = null;
            ModifingInfo info = null;
            if (FormatSelf(ref mi, ref info))
            {
                if (masterEditor != null)
                {
                    masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.MoveWidgets;
                }
                return;//格式刷格式化，不更改选定状态。
            }

            KeyStates ksRightShift = Keyboard.GetKeyStates(Key.RightShift);
            KeyStates ksLeftShift = Keyboard.GetKeyStates(Key.LeftShift);

            bool isShift = false;

            if ((ksRightShift & KeyStates.Down) > 0 || (ksLeftShift & KeyStates.Down) > 0) { isShift = true; }

            bool isCtrl = false;
            KeyStates ksRightCtrl = Keyboard.GetKeyStates(Key.RightCtrl);
            KeyStates ksLeftCtrl = Keyboard.GetKeyStates(Key.LeftCtrl);

            if ((ksRightCtrl & KeyStates.Down) > 0 || (ksLeftCtrl & KeyStates.Down) > 0) isCtrl = true;

            if (isShift && isCtrl == false)
            {
                //基本规则：
                //    ①如果未选定，选定，并作为活动部件。
                //    ②如果已选定，看是否是活动部件，如果已经是活动部件，整个取消选定状态；
                //                                      如果不是活动部件，设为活动部件。
                if (this.IsSelected == false)
                {
                    this.IsMainSelected = true;
                }
                else
                {
                    if (this.IsMainSelected == false)
                    {
                        this.IsMainSelected = true;
                    }
                    else
                    {
                        this.IsSelected = false;
                    }
                }
            }
            else
            {
                if (IsSelected == false)
                {
                    this.SelectOnlySelf();
                }
                //如果是选定的部件，那么可能是在拖动。
            }

            //准备拖动。
            if (masterEditor != null)
            {
                masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.MoveWidgets;
                Point pt = e.GetPosition(this.masterEditor);
                pt = new Point(pt.X - this.masterEditor.BorderThickness.Left, pt.Y - this.masterEditor.BorderThickness.Top);
                masterEditor.MouseInfo.LeftButtonPreviewPoint = pt;
            }
        }

        void mainRectangle_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;

            if (this.IsSelected == false)
            {
                //如果未选定，就作为活动，
                this.SelectOnlySelf();
            }
            else
            {
                //若已选定，不更改选定范围，只更改“活动部件”为此部件
                if (this.IsMainSelected == false) this.IsMainSelected = true;
            }

            if (this.ContextMenu != null)
            {
                this.ContextMenu.IsOpen = true;
            }
        }

        /// <summary>
        /// 还需要解决标记文本[折叠、展开]切换的问题。
        /// </summary>
        void markAdorner_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            mainRectangle_PreviewMouseLeftButtonDown(sender, e);

            KeyStates ksRightShift = Keyboard.GetKeyStates(Key.RightShift);
            KeyStates ksLeftShift = Keyboard.GetKeyStates(Key.LeftShift);

            bool isShift = false;

            if ((ksRightShift & KeyStates.Down) > 0 || (ksLeftShift & KeyStates.Down) > 0) { isShift = true; }

            bool isCtrl = false;
            KeyStates ksRightCtrl = Keyboard.GetKeyStates(Key.RightCtrl);
            KeyStates ksLeftCtrl = Keyboard.GetKeyStates(Key.LeftCtrl);

            if ((ksRightCtrl & KeyStates.Down) > 0 || (ksLeftCtrl & KeyStates.Down) > 0) isCtrl = true;

            if (isCtrl || isShift) return;

            if (this.IsMarkTextCollapsed)
            {
                Commands.SetMarkTextExpandCommand.Execute();
            }
            else
            {
                Commands.SetMarkTextCollapseCommand.Execute();
            }
        }

        /// <summary>
        /// 准备拖出“关系（由两条直线、两个新文本框组成，或由一个文本框、一条直线组成）。
        /// </summary>
        void centerAdorner_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (masterEditor == null) return;
            if (e.ClickCount == 2)
            {
                //防止误拖动部件。
                if (masterEditor != null && masterEditor.MasterManager != null)
                {
                    masterEditor.MouseInfo.DraggingType = masterEditor.MasterManager.MouseDraggingType;
                }

                this.SelectOnlySelf();
                if (Globals.MainWindow.IsPresentatingByPath == false)
                {
                    this.Edit();
                }
                return;
            }

            e.Handled = true;
            if (Globals.MainWindow != null && Globals.MainWindow.EditorManager != null)
            {
                switch (Globals.MainWindow.EditorManager.MouseDraggingType)
                {
                    case PageDraggingType.InsertBezierLine:
                        {
                            masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.InsertBezierLineRelation;
                            break;
                        }
                    case PageDraggingType.InsertPolyLine:
                        {
                            masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.InsertPolyLineRelation;
                            break;
                        }
                    default:
                        {
                            masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.InsertStraitLineRelation;
                            break;
                        }
                }
            }
            else
            {
                masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.InsertStraitLineRelation;
            }

            //Point pt = e.GetPosition(this.masterEditor);//这个不好，会偏
            //pt = new Point(pt.X - this.masterEditor.BorderThickness.Left,
            //    pt.Y - this.masterEditor.BorderThickness.Top);

            Point pt = this.Center;//直接用中心点更好。
            masterEditor.MouseInfo.LeftButtonPreviewPoint = pt;
            masterEditor.MouseInfo.MainSelectedWidget = this;
        }

        public override void CollapseToTop(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            if (startPoint.Y > endPoint.Y)
            {
                Point newStartPoint = new Point(startPoint.X, startPoint.Y - units);
                Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                    startPoint.ToString(), newStartPoint.ToString());
                StartPoint = newStartPoint;

                mi.AddAction(actStartPoint);
            }
            else if (startPoint.Y < endPoint.Y)
            {
                Point newEndPoint = new Point(endPoint.X, endPoint.Y - units);
                Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                    endPoint.ToString(), newEndPoint.ToString());
                EndPoint = newEndPoint;

                mi.AddAction(actEndPoint);
            }
            //如果水平对齐，则不更改。
        }

        public override void ExpandToBottom(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            if (startPoint.Y > endPoint.Y)
            {
                Point newStartPoint = new Point(startPoint.X, startPoint.Y + units);
                Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                    startPoint.ToString(), newStartPoint.ToString());
                StartPoint = newStartPoint;

                mi.AddAction(actStartPoint);
            }
            else if (startPoint.Y < endPoint.Y)
            {
                Point newEndPoint = new Point(endPoint.X, endPoint.Y + units);
                Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                    endPoint.ToString(), newEndPoint.ToString());
                EndPoint = newEndPoint;

                mi.AddAction(actEndPoint);
            }
            //如果水平对齐，则不更改。
        }

        public override void CollapseToLeft(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            if (startPoint.X > endPoint.X)
            {
                Point newStartPoint = new Point(startPoint.X - units, startPoint.Y);
                Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                    startPoint.ToString(), newStartPoint.ToString());
                StartPoint = newStartPoint;

                mi.AddAction(actStartPoint);
            }
            else if (startPoint.X < endPoint.X)
            {
                Point newEndPoint = new Point(endPoint.X - units, endPoint.Y);
                Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                    endPoint.ToString(), newEndPoint.ToString());
                EndPoint = newEndPoint;

                mi.AddAction(actEndPoint);
            }
            //如果垂直对齐，则不更改
        }

        public override void ExpandToRight(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            if (startPoint.X > endPoint.X)
            {
                Point newStartPoint = new Point(startPoint.X + units, startPoint.Y);
                Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                    startPoint.ToString(), newStartPoint.ToString());
                StartPoint = newStartPoint;

                mi.AddAction(actStartPoint);
            }
            else if (startPoint.X < endPoint.X)
            {
                Point newEndPoint = new Point(endPoint.X + units, endPoint.Y);
                Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                    endPoint.ToString(), newEndPoint.ToString());
                EndPoint = newEndPoint;

                mi.AddAction(actEndPoint);
            }
            //如果垂直对齐，则不更改
        }

        public override bool FormatSelf(ref ModifingItem<Action, ModifingInfo> mi, ref ModifingInfo info)
        {
            if (this.masterEditor == null || this.masterEditor.MasterManager == null) return false;

            EditorManager manager = this.masterEditor.MasterManager;
            if (manager.FormatBrush == null) return false;//不在“格式刷”状态

            PageEditor mainPageEditor = this.masterEditor;

            List<Widgets.Widget> destWidgets = new List<Widget>();
            destWidgets.Add(this);//格式化功能只需要自身一个即可。不更改兄弟部件的选定状态。

            if (info == null)
            {
                info = new ModifingInfo();
                info.ModifingDescription = "格式化部件";
                manager.GetSelectedPageEditorStatus(info);
                manager.GetSelectedWidgetStatus_Old(info);
                manager.GetSelectedWidgetStatus_New(info);
            }

            bool shouldReg = false;
            if (mi == null)
            {
                shouldReg = true;
                mi = new ModifingItem<Action, ModifingInfo>(info);
            }

            //设置格式
            Action actOpacity = new Action(mainPageEditor.Id, this.id, this.GetType().Name, XmlTags.WidgetOpacityTag,
                this.WidgetOpacity.ToString(), manager.FormatBrush.DefaultWidgetStyle.WidgetOpacity.ToString());
            this.WidgetOpacity = manager.FormatBrush.DefaultWidgetStyle.WidgetOpacity;

            Action actBackColor = new Action(mainPageEditor.Id, this.id, this.GetType().Name, XmlTags.WidgetBackColor,
                BrushManager.GetName(this.WidgetBackColor),
                BrushManager.GetName(manager.FormatBrush.DefaultWidgetStyle.WidgetBackColor));
            this.WidgetBackColor = manager.FormatBrush.DefaultWidgetStyle.WidgetBackColor;

            Action actForeColor = new Action(mainPageEditor.Id, this.id, this.GetType().Name, XmlTags.WidgetForeColor,
                BrushManager.GetName(this.WidgetForeColor),
                BrushManager.GetName(manager.FormatBrush.DefaultWidgetStyle.WidgetForeColor));
            this.WidgetForeColor = manager.FormatBrush.DefaultWidgetStyle.WidgetForeColor;

            Action actLineColor = new Action(mainPageEditor.Id, this.id, this.GetType().Name, XmlTags.WidgetLineColorTag,
                BrushManager.GetName(this.WidgetLineColor),
                BrushManager.GetName(manager.FormatBrush.DefaultWidgetStyle.WidgetLineColor));
            this.WidgetLineColor = manager.FormatBrush.DefaultWidgetStyle.WidgetLineColor;

            Action actLineWidth = new Action(mainPageEditor.Id, this.id, this.GetType().Name, XmlTags.WidgetLineWidthTag,
                this.WidgetLineWidth.ToString(), manager.FormatBrush.DefaultWidgetStyle.WidgetLineWidth.ToString());
            this.WidgetLineWidth = manager.FormatBrush.DefaultWidgetStyle.WidgetLineWidth;

            Action actLineDash = new Action(mainPageEditor.Id, this.id, this.GetType().Name, XmlTags.LineDashTag,
                this.LineDash.ToString(), manager.FormatBrush.DefaultWidgetStyle.LineDash.ToString());
            this.LineDash = manager.FormatBrush.DefaultWidgetStyle.LineDash;

            Action actIsShadowVisible = new Action(mainPageEditor.Id, this.id, this.GetType().Name, XmlTags.IsShadowVisibleTag,
                this.IsShadowVisible.ToString(), manager.FormatBrush.DefaultWidgetStyle.IsShadowVisible.ToString());
            this.IsShadowVisible = manager.FormatBrush.DefaultWidgetStyle.IsShadowVisible;

            Action actRadius = new Action(mainPageEditor.Id, this.id, this.GetType().Name, XmlTags.RadiusTag,
                this.Radius.ToString(), manager.FormatBrush.DefaultWidgetStyle.Radius.ToString());
            this.Radius = manager.FormatBrush.DefaultWidgetStyle.Radius;

            mi.AddAction(actOpacity); mi.AddAction(actBackColor); mi.AddAction(actForeColor); mi.AddAction(actLineColor);
            mi.AddAction(actLineDash); mi.AddAction(actLineWidth); mi.AddAction(actIsShadowVisible); mi.AddAction(actRadius);

            if (shouldReg)
            {
                manager.RegisterModifingItem(mi);

                if (manager.FormatBrush.OnlyFormatOnceTime)
                {
                    masterEditor.RaiseWidgetFormated(new List<Widgets.Widget>() { this });
                }
            }

            return true;
        }

        public override void MoveUp(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y - units);
            Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y - units);
            Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            EndPoint = newEndPoint;

            mi.AddAction(actStartPoint);
            mi.AddAction(actEndPoint);
        }

        public override void MoveDown(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y + units);
            Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y + units);
            Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            EndPoint = newEndPoint;

            mi.AddAction(actStartPoint);
            mi.AddAction(actEndPoint);
        }

        public override void MoveLeft(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            Point newStartPoint = new Point(startPoint.X - units, startPoint.Y);
            Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X - units, endPoint.Y);
            Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            EndPoint = newEndPoint;

            mi.AddAction(actStartPoint);
            mi.AddAction(actEndPoint);
        }

        public override void MoveRight(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            Point newStartPoint = new Point(startPoint.X + units, startPoint.Y);
            Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X + units, endPoint.Y);
            Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            EndPoint = newEndPoint;

            mi.AddAction(actStartPoint);
            mi.AddAction(actEndPoint);
        }

        /// <summary>
        /// 改变中心点横坐标。
        /// </summary>
        public override void MoveHorizontalCenterTo(ModifingItem<Action, ModifingInfo> mi, double center)
        {
            if (mi == null || double.IsNaN(center) || masterEditor == null) return;

            double offset = 0;
            double curCenter = TopLeft.X + (BottomRight.X - TopLeft.X) / 2;
            offset = curCenter - center;

            Point newStartPoint = new Point(startPoint.X - offset, startPoint.Y);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X - offset, endPoint.Y);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 改变中心点纵坐标。
        /// </summary>
        public override void MoveVerticalCenterTo(ModifingItem<Action, ModifingInfo> mi, double center)
        {
            if (mi == null || double.IsNaN(center) || masterEditor == null) return;

            double offset = 0;
            double curCenter = TopLeft.Y + (BottomRight.Y - TopLeft.Y) / 2;
            offset = curCenter - center;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y - offset);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y - offset);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 与MoveDown不同，这里是指定向下移动到哪个位置（下边缘到哪个位置）。
        /// </summary>
        public override void MoveBottomSiderTo(ModifingItem<Action, ModifingInfo> mi, double bottom)
        {
            if (mi == null || double.IsNaN(bottom) || masterEditor == null) return;

            double offset = 0;
            double maxBottom = BottomRight.Y;
            offset = maxBottom - bottom;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y - offset);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y - offset);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 与MoveLeft不同，这里是指定向左移动到哪个位置（左边缘到哪个位置）。
        /// </summary>
        public override void MoveLeftSiderTo(ModifingItem<Action, ModifingInfo> mi, double left)
        {
            if (mi == null || double.IsNaN(left) || masterEditor == null) return;

            double offset = 0;
            double minLeft = TopLeft.X;
            offset = minLeft - left;

            Point newStartPoint = new Point(startPoint.X - offset, startPoint.Y);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X - offset, endPoint.Y);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 与MoveRight不同，这里是指定向右移动到哪个位置（右边缘到哪个位置）。
        /// </summary>
        public override void MoveRightSiderTo(ModifingItem<Action, ModifingInfo> mi, double right)
        {
            if (mi == null || double.IsNaN(right) || masterEditor == null) return;

            double offset = 0;
            double maxRight = BottomRight.X;
            offset = maxRight - right;

            Point newStartPoint = new Point(startPoint.X - offset, startPoint.Y);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X - offset, endPoint.Y);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 与MoveUp不同，这里是指定向上移动到哪个位置（上边缘到哪个位置）。
        /// </summary>
        public override void MoveTopSiderTo(ModifingItem<Action, ModifingInfo> mi, double top)
        {
            if (mi == null || double.IsNaN(top) || masterEditor == null) return;

            double offset = 0;
            double minTop = TopLeft.Y;
            offset = minTop - top;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y - offset);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y - offset);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actEnd);
        }

        public override void MoveWhenDraggingControler(Point newOutSidePoint)
        {
            bool isShift = false;

            KeyStates ksRightShift = Keyboard.GetKeyStates(Key.RightShift);
            KeyStates ksLeftShift = Keyboard.GetKeyStates(Key.LeftShift);

            if ((ksLeftShift & KeyStates.Down) > 0 || (ksRightShift & KeyStates.Down) > 0)
            {
                isShift = true;
            }

            Point point1, point2;
            switch (draggingType)
            {
                case ControlDraggingType.Start:
                    {
                        Point newMovingPoint = newOutSidePoint;
                        DrawLine(newMovingPoint, this.endPoint, isShift);
                        point1 = newMovingPoint;
                        point2 = this.endPoint;
                        break;
                    }
                default:// ControlDraggingType.End:
                    {
                        Point newMovingPoint = newOutSidePoint;
                        DrawLine(this.startPoint, newMovingPoint, isShift);
                        point1 = this.StartPoint;
                        point2 = newMovingPoint;
                        break;
                    }
            }

            LocateTextPanel(point1, point2);
        }

        /// <summary>
        /// 取与自身挂接的连接线。
        /// </summary>
        /// <returns>可能返回null。</returns>
        public List<ILinkableLine> GetLinkedLines()
        {
            if (this.masterEditor == null) return null;

            List<Widget> widgets = new List<Widget>();
            widgets.Add(this);

            return this.masterEditor.GetLinkedLines(widgets);
        }

        public override string GetRelativeOuterXml(Point baseCopyTopLeft)
        {
            if (this.xmlData == null) return string.Empty;

            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X - baseCopyTopLeft.X,
                oldStartPoint.Y - baseCopyTopLeft.Y);
            this.xmlData.SetAttribute(XmlTags.StartPointTag, newStartPoint.ToString());

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X - baseCopyTopLeft.X,
                oldEndPoint.Y - baseCopyTopLeft.Y);
            this.xmlData.SetAttribute(XmlTags.EndPointTag, newEndPoint.ToString());

            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append(this.xmlData.OuterXml);

            this.xmlData.SetAttribute(XmlTags.StartPointTag, oldStartPoint.ToString());
            this.xmlData.SetAttribute(XmlTags.EndPointTag, oldEndPoint.ToString());

            return sb.ToString();
        }

        public override void MoveWhenDraggingWidget(Point mousePoint)
        {
            if (masterEditor == null || masterEditor.MasterManager == null) return;

            Point newMovingPoint = mousePoint;
            Point globalLocation = masterEditor.MouseInfo.LeftButtonPreviewPoint;

            Point tmpStartPoint = new Point(startPoint.X - globalLocation.X + newMovingPoint.X,
                startPoint.Y - globalLocation.Y + newMovingPoint.Y);
            Point tmpEndPoint = new Point(endPoint.X - globalLocation.X + newMovingPoint.X,
                endPoint.Y - globalLocation.Y + newMovingPoint.Y);

            DrawLine(tmpStartPoint, tmpEndPoint, false);

            LocateTextPanel(tmpStartPoint, tmpEndPoint);
        }

        /// <summary>
        /// 刷新所有控制点。
        /// </summary>
        public override void RefreshControlers()
        {
            if (isSelected)
            {
                //刷新控制点色彩
                if (masterEditor != null && masterEditor.MasterManager != null)
                {
                    if (startCtrl.MainSelectedBrush != masterEditor.MasterManager.WidgetStartControlerBrush)
                        startCtrl.MainSelectedBrush = masterEditor.MasterManager.WidgetStartControlerBrush;

                    if (endCtrl.MainSelectedBrush != masterEditor.MasterManager.WidgetEndControlerBrush)
                        endCtrl.MainSelectedBrush = masterEditor.MasterManager.WidgetEndControlerBrush;
                }

                Point topLeft = TopLeft;
                startCtrl.CenterPoint = new Point(startPoint.X - TopLeft.X, startPoint.Y - topLeft.Y);
                endCtrl.CenterPoint = new Point(endPoint.X - TopLeft.X, endPoint.Y - topLeft.Y);

                startCtrl.Visibility =
                    endCtrl.Visibility = System.Windows.Visibility.Visible;
            }
            else
            {
                startCtrl.Visibility =
                    endCtrl.Visibility = System.Windows.Visibility.Hidden;
            }
        }

        public override void RefreshLineDash()
        {
            if (this.isPresentationArea)
            {
                //演示区域边框总是划线。
                this.mainRectangle.StrokeDashArray = LineDashType.dashCollection;
                return;
            }

            switch (lineDash)
            {
                case LineDashType.DashType.Dash:
                    {
                        this.mainRectangle.StrokeDashArray = LineDashType.dashCollection; break;
                    }
                case LineDashType.DashType.DashDotDot:
                    {
                        this.mainRectangle.StrokeDashArray = LineDashType.dashDotDotCollection; break;
                    }
                case LineDashType.DashType.Dot:
                    {
                        this.mainRectangle.StrokeDashArray = LineDashType.dotCollection; break;
                    }
                case LineDashType.DashType.Solid:
                    {
                        this.mainRectangle.StrokeDashArray = LineDashType.solidCollection; break;
                    }
                default:
                    {
                        this.mainRectangle.StrokeDashArray = LineDashType.dashDotCollection; break;
                    }
            }
        }

        /// <summary>
        /// 此方法本是专门为矩形提供的，用于在EditorManager.DefaultFontSize发生变化时刷新相关的值。
        /// </summary>
        public override void RefreshDefaultFontSize()
        {
            base.RefreshDefaultFontSize();

            this.RefreshMarkText();//使用了EditorManager.DefaultFontSize.
        }

        /// <summary>
        /// 在移动控制点时刷新文本面板宽度。
        /// </summary>
        private void RefreshFixTextWidth()
        {
            RefreshFixTextWidth(this.StartBasePoint, this.EndBasePoint);
        }

        private void RefreshFixTextWidth(Point startBasePt, Point endBasePt)
        {
            if (fixTextWidth)
            {
                double rectangleWidth = Math.Abs(endBasePt.X - startBasePt.X);

                if (rectangleWidth < 24)
                {
                    this.mainTextPanel.Width = 20;
                }
                else
                {
                    this.mainTextPanel.Width = rectangleWidth - 4 - this.widgetLineWidth * 2;
                }

                foreach (UIElement ue in this.mainTextPanel.Children)
                {
                    TextBlock tbk = ue as TextBlock;
                    if (tbk == null) continue;

                    if (tbk.TextWrapping != TextWrapping.Wrap)
                    {
                        tbk.TextWrapping = TextWrapping.Wrap;
                    }
                }
            }
            else
            {
                this.mainTextPanel.Width = double.NaN;

                foreach (UIElement ue in this.mainTextPanel.Children)
                {
                    TextBlock tbk = ue as TextBlock;
                    if (tbk == null) continue;

                    if (tbk.TextWrapping != TextWrapping.NoWrap)
                    {
                        tbk.TextWrapping = TextWrapping.NoWrap;
                    }
                }
            }
        }

        /// <summary>
        /// 刷新矩形的线宽。
        /// </summary>
        public override void RefreshWidgetLineWidth()
        {
            mainRectangle.StrokeThickness = widgetLineWidth;

            if (this.fixTextWidth)
            {
                RefreshTextPanelLocatin();
            }
        }

        private FrameworkElement xamlIconFrameWorkElement = null;

        /// <summary>
        /// 刷新IconXamlText(载入图标）。
        /// </summary>
        /// <returns>如果正常执行，返回string.Empty。否则返回异常信息。</returns>
        private void RefreshIconXamlText()
        {
            if (this.mainCanvas.Children.Contains(xamlIconFrameWorkElement))
            {
                this.mainCanvas.Children.Remove(xamlIconFrameWorkElement);
                xamlIconFrameWorkElement = null;
            }

            if (this.iconXamlText != null && this.iconXamlText.Length > 0)
            {
                var txt = this.iconXamlText.Replace("&lt;", "<").Replace("&gt;", ">").Replace("&amp;lt;", "<").Replace("&amp;gt;", ">");

                byte[] array = System.Text.Encoding.UTF8.GetBytes(txt);

                try
                {
                    using (var stream = new System.IO.MemoryStream(array))
                    {
                        this.xamlIconFrameWorkElement = System.Windows.Markup.XamlReader.Load(stream) as FrameworkElement;

                        this.xamlIconFrameWorkElement.MouseLeftButtonDown += mainRectangle_PreviewMouseLeftButtonDown;

                        Canvas.SetLeft(this.xamlIconFrameWorkElement, this.OuterRect.Left);
                        Canvas.SetTop(this.xamlIconFrameWorkElement, this.OuterRect.Top);

                        this.xamlIconFrameWorkElement.Width = this.OuterRect.Width;
                        this.xamlIconFrameWorkElement.Height = this.OuterRect.Height;

                        this.mainCanvas.Children.Add(this.xamlIconFrameWorkElement);
                    }
                }
                catch (Exception ex)
                {
                    throw ex;//异常不能在此处处理，否则SetRantangleXamlText.Execute()方法啥的就没法子处理异常了。
                }
            }
        }

        public override void RefreshLocation()
        {
            base.RefreshLocation();

            DrawLine();

            //Point startBasePt = StartBasePoint;
            //Point endBasePt = EndBasePoint;
            //Canvas.SetLeft(mainRectangle, startBasePt.X);
            //Canvas.SetTop(mainRectangle, startBasePt.Y);

            //mainRectangle.Width = (endBasePt.X - startBasePt.X);
            //mainRectangle.Height = (endBasePt.Y - startBasePt.Y);

            //this.movingRect = new Rect(startPoint, endPoint);

            RefreshWidgetLineWidth();
            RefreshControlers();

            RefreshMarkText();
            RefreshIsPresentationArea();

            RefreshRadius(this.OuterRect);
            RefreshIconXamlText();
        }

        public void RefreshMarkText(Rect? rect = null)
        {
            if (this.markAdorner == null) return;

            if (string.IsNullOrEmpty(this.markText))
            {
                this.markAdorner.InvalidateVisual(); return;
            }

            if (rect == null)
            {
                this.markAdorner.MasterRect = this.RealRect;
            }
            else
            {
                this.markAdorner.MasterRect = rect.Value;
            }

            this.markAdorner.InvalidateVisual();
        }

        public void RefreshIsPresentationArea(Rect? rect = null)
        {
            if (this.presentationAreaAdorner == null) return;

            if (isPresentationArea)
            {
                this.presentationAreaAdorner.Visibility = Visibility.Visible;
            }
            else
            {
                this.presentationAreaAdorner.Visibility = Visibility.Hidden;
            }

            if (rect == null)
            {
                this.presentationAreaAdorner.MasterRect = this.RealRect;
            }
            else
            {
                this.presentationAreaAdorner.MasterRect = rect.Value;
            }

            this.presentationAreaAdorner.InvalidateVisual();

            if (isPresentationArea)
            {
                this.mainRectangle.Fill = null;
                this.mainRectangle.StrokeDashArray = LineDashType.dashCollection;
            }
            else
            {
                RefreshWidgetBackColor();
                RefreshLineDash();
            }
        }

        public override void RefreshPointWhenGroupIn(Point baseTopLeft)
        {
            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X - baseTopLeft.X,
                oldStartPoint.Y - baseTopLeft.Y);
            StartPoint = newStartPoint;

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X - baseTopLeft.X,
                oldEndPoint.Y - baseTopLeft.Y);
            EndPoint = newEndPoint;
        }

        public override void RefreshPointWhenGroupOut(Point baseTopLeft)
        {
            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X + baseTopLeft.X,
                oldStartPoint.Y + baseTopLeft.Y);
            StartPoint = newStartPoint;

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X + baseTopLeft.X,
                oldEndPoint.Y + baseTopLeft.Y);
            EndPoint = newEndPoint;
        }

        public void RefreshRadius(Rect rect)
        {
            if (this.mainRectangle == null) return;
            if (radius > 0)
            {
                double k = (radius % 1);//取小数。
                if (k == 0) k = 1;

                double r = Math.Min(rect.Width, rect.Height) * k;

                this.mainRectangle.RadiusX =
                    this.mainRectangle.RadiusY = r;
            }
            else
            {
                this.mainRectangle.RadiusX =
                 this.mainRectangle.RadiusY = 0;
            }
        }

        public override void RefreshIsShadowVisible()
        {
            //base.RefreshIsShadowVisible();//保持文本清晰

            if (isShadowVisible)
            {
                this.mainRectangle.Effect = Widget.ShadowEffect;
            }
            else
            {
                this.mainRectangle.Effect = null;
            }
        }

        public override void RefreshTextPanelLocatin()
        {
            LocateTextPanel(this.StartBasePoint, this.EndBasePoint);
        }

        /// <summary>
        /// 刷新文本区旋转角度。
        /// </summary>
        public void RefreshTextRotateAngle()
        {
            if (this.mainTextPanel.RenderTransformOrigin != DefaultRenderCenter)
            {
                this.mainTextPanel.RenderTransformOrigin = DefaultRenderCenter;
            }

            if (this.textRotateAngle == 0)
            {
                this.mainTextPanel.RenderTransform = DefaultRotateTransform;
            }
            else
            {
                this.mainTextPanel.RenderTransform = new RotateTransform(textRotateAngle);
            }
        }

        public override void RefreshWidgetBackColor()
        {
            base.RefreshWidgetBackColor();
            if (widgetBackColor == Brushes.Transparent || this.isPresentationArea)
            {
                this.mainRectangle.Fill = null;
            }
            else
            {
                this.mainRectangle.Fill = widgetBackColor;
            }

            this.markAdorner?.InvalidateVisual();

            //矩形要考虑气泡
            this.RefreshTextPanelLocatin();
        }

        public override void RefreshWidgetLineColor()
        {
            this.mainRectangle.Stroke = widgetLineColor;
        }

        /// <summary>
        /// 是否重置矩形的宽、高。只有在“FixTextWidth”为false时才会执行。
        /// </summary>
        internal static void ResetRectangleSize(ModifingItem<Action, ModifingInfo> mi, Widgets.RectangleWidget rw)
        {
            if (mi == null || rw == null || rw.FixTextWidth || rw.MasterEditor == null) return;

            if (rw.StartPoint.X > rw.EndPoint.X || rw.StartPoint.Y > rw.EndPoint.Y)
            {
                Point ptStart = rw.TopLeft;
                Point ptEnd = rw.BottomRight;

                Action actStartPoint = new Action(rw.MasterEditor.Id, rw.id, rw.GetType().Name, XmlTags.StartPointTag,
                    rw.StartPoint.ToString(), ptStart.ToString());
                rw.StartPoint = ptStart;

                Action actEndPoint = new Action(rw.MasterEditor.Id, rw.id, rw.GetType().Name, XmlTags.EndPointTag,
                    rw.EndPoint.ToString(), ptEnd.ToString());
                rw.EndPoint = ptEnd;

                mi.AddAction(actStartPoint);
                mi.AddAction(actEndPoint);
            }

            //先按文本区所需要的尺寸调整矩形大小。
            Rect r = rw.RealRect;

            double needHeight;
            double needWidth;

            if (rw.mainTextPanel != null)
            {
                rw.mainTextPanel.InvalidateArrange(); rw.mainTextPanel.UpdateLayout();
                needHeight = rw.mainTextPanel.ActualHeight + 4;
                needWidth = rw.mainTextPanel.ActualWidth + 8;
                if (needHeight < 20) needHeight = 20;
                if (needWidth < 10) needWidth = 10;
            }
            else
            {
                needWidth = 10; needHeight = 20;
            }

            if (needHeight != r.Height || needWidth != r.Width)
            {
                Point sPt = rw.StartPoint;
                Point newEndPt = new Point(sPt.X + needWidth, sPt.Y + needHeight);
                Action actNewEnd = new Action(rw.MasterEditor.Id, rw.id, rw.GetType().Name, XmlTags.EndPointTag,
                    rw.EndPoint.ToString(), newEndPt.ToString());
                rw.EndPoint = newEndPt;

                mi.AddAction(actNewEnd);
            }
        }

        /// <summary>
        /// 矩形部件的“FixTextWidth”为真时才会执行。
        /// 格式化矩形框的底边，使之适应内部的文本。
        /// </summary>
        /// <param name="mi"></param>
        /// <param name="rw"></param>
        internal static void ResetRectangleWidgetHeight(ModifingItem<Action, ModifingInfo> mi, Widgets.RectangleWidget rw)
        {
            //判断是否需要重置下边缘。
            Point startPoint = rw.StartPoint;
            Point endPoint = rw.EndPoint;
            if (rw.FixTextWidth)
            {
                if (startPoint.Y < endPoint.Y)
                {
                    //更改EndPoint值，以适应文本高度。
                    Point newBottomPoint = new Point(endPoint.X, startPoint.Y + 4 + rw.WidgetLineWidth * 2 + rw.TextPanelHeight);
                    Action actPt = new Action(rw.MasterEditor.Id, rw.Id, rw.GetType().Name, XmlTags.EndPointTag,
                        endPoint.ToString(), newBottomPoint.ToString());
                    rw.EndPoint = newBottomPoint;

                    mi.AddAction(actPt);
                }
                else
                {
                    //更改StartPoint值，以适应文本高度。
                    Point newBottomPoint = new Point(startPoint.X, endPoint.Y + 4 + rw.WidgetLineWidth * 2 + rw.TextPanelHeight);
                    Action actPt = new Action(rw.MasterEditor.Id, rw.Id, rw.GetType().Name, XmlTags.StartPointTag,
                        startPoint.ToString(), newBottomPoint.ToString());
                    rw.StartPoint = newBottomPoint;

                    mi.AddAction(actPt);
                }
            }
        }

        /// <summary>
        /// 统一选定矩形部件的宽度。
        /// </summary>
        internal static void ResetRectangleWidgetWidth(ModifingItem<Action, ModifingInfo> mi, Widgets.RectangleWidget rw, double maxWidth)
        {
            Point startPoint = rw.StartPoint;
            Point endPoint = rw.EndPoint;
            if (Math.Abs(endPoint.X - startPoint.X) == maxWidth) return;

            if (startPoint.X < endPoint.X)
            {
                // 更改EndPoint值，以统一宽度。
                Point newEndPoint = new Point(startPoint.X + maxWidth, endPoint.Y);
                Action actPt = new Action(rw.MasterEditor.Id, rw.Id, rw.GetType().Name, XmlTags.EndPointTag,
                    endPoint.ToString(), newEndPoint.ToString());
                rw.EndPoint = newEndPoint;

                mi.AddAction(actPt);
            }
            else
            {
                // 更改StartPoint值，以统一宽度。
                Point newStartPoint = new Point(endPoint.X + maxWidth, startPoint.Y);
                Action actPt = new Action(rw.MasterEditor.Id, rw.Id, rw.GetType().Name, XmlTags.StartPointTag,
                    startPoint.ToString(), newStartPoint.ToString());
                rw.StartPoint = newStartPoint;

                mi.AddAction(actPt);
            }
        }

        public override void UpdatePointsWhenPasting(Point basePasteTopLeft)
        {
            Point newStartPoint = new Point(startPoint.X + basePasteTopLeft.X,
               startPoint.Y + basePasteTopLeft.Y);

            StartPoint = newStartPoint;

            Point newEndPoint = new Point(endPoint.X + basePasteTopLeft.X,
                endPoint.Y + basePasteTopLeft.Y);

            EndPoint = newEndPoint;
        }

        void endCtrl_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (e.ClickCount == 2)
            {
                OnControlHandlerDoubleClicked(sender, e);
                e.Handled = true;
                return;
            }

            if (masterEditor == null) return;

            this.SelectOnlySelf();

            //开始拖动。
            e.Handled = true;
            masterEditor.MouseInfo.LeftButtonPreviewPoint = StartPoint;
            masterEditor.MouseInfo.DraggingType = PageDraggingType.MoveLineWidgetControler;
            draggingType = ControlDraggingType.End;

            endCtrl.Visibility = System.Windows.Visibility.Hidden;
        }

        public event EventHandler<MouseButtonEventArgs> ControlHandlerDoubleClicked;

        protected void OnControlHandlerDoubleClicked(object sender, MouseButtonEventArgs e)
        {
            if (ControlHandlerDoubleClicked != null)
            {
                ControlHandlerDoubleClicked(sender, e);
            }
        }

        void startCtrl_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (e.ClickCount == 2)
            {
                OnControlHandlerDoubleClicked(sender, e);
                e.Handled = true;
                return;
            }

            if (masterEditor == null) return;

            this.SelectOnlySelf();

            //开始拖动。
            e.Handled = true;
            masterEditor.MouseInfo.LeftButtonPreviewPoint = StartPoint;
            masterEditor.MouseInfo.DraggingType = PageDraggingType.MoveLineWidgetControler;
            draggingType = ControlDraggingType.Start;

            startCtrl.Visibility = System.Windows.Visibility.Hidden;
        }

        #endregion


        #region 其它=========================================================================================================

        /// <summary>
        /// 表示拖动哪个控制点。
        /// </summary>
        private enum ControlDraggingType { Start, CenterCP, End, None }

        #endregion

    }
}
